﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;

namespace GoodStuff.Validation
{
    public class AttributeBasedRuleSet<TEntity> : IRuleBuilder<TEntity> where TEntity : class
    {
        IList<IValidationRule<TEntity>> rules = new List<IValidationRule<TEntity>>();

        public static readonly IDictionary<Type, Func<Func<TEntity, string>, IValidationRule<TEntity>>> Mapping = 
            new Dictionary<Type, Func<Func<TEntity, string>, IValidationRule<TEntity>>>()
        {
            { typeof(RequiredAttribute), p => new Rules.PropertyValidator<TEntity,string>(p, new Rules.IsRequiredRule()) },
            { typeof(StringLengthAttribute), p => new Rules.PropertyValidator<TEntity,string>(p, new Rules.StringLengthRule(20)) }
        };

        public AttributeBasedRuleSet()
        {
            Type t = typeof(TEntity);

            //enumerate all properties that have an validation attribute.
            foreach (var property in t.GetProperties<ValidationAttribute>())
            {
                ParameterExpression pe = Expression.Parameter(t, "p");
                Expression body = Expression.Property(pe, property.Name);
                var lambda = Expression.Lambda<Func<TEntity, string>>(body, pe);

                Func<TEntity, string> f = lambda.Compile();

                foreach (var attribute in property.GetAttributes<ValidationAttribute>())
                {  
                    if(Mapping.ContainsKey(attribute.GetType()))
                    {
                        Func<Func<TEntity,string>, IValidationRule<TEntity>> rule = Mapping[attribute.GetType()];
                        IValidationRule<TEntity> newRule = rule(f);
                        rules.Add(newRule);
                    }
                }
            }
        }

        public IList<IValidationRule<TEntity>> GetRules()
        {
            return rules;
        }
    }
}
